# 五子棋人机对战 HTML 游戏

以下是一个完整的五子棋人机对战游戏 HTML 文件，包含了所有必要的 HTML、CSS 和 JavaScript 代码。这个游戏实现了：

1. 人机对战功能
2. 可选择玩家先手或电脑先手
3. 电脑有基本的 AI 算法
4. 游戏胜负判定
5. 重新开始功能

```html
<!DOCTYPE html>
<html lang="zh-CN">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>五子棋人机对战</title>
    <style>
        body {
            font-family: 'Microsoft YaHei', sans-serif;
            display: flex;
            flex-direction: column;
            align-items: center;
            background-color: #f5f5dc;
            margin: 0;
            padding: 20px;
        }
        h1 {
            color: #8b4513;
            margin-bottom: 10px;
        }
        .game-container {
            display: flex;
            flex-direction: column;
            align-items: center;
            margin-top: 20px;
        }
        .controls {
            margin-bottom: 20px;
            display: flex;
            gap: 20px;
        }
        button {
            padding: 8px 16px;
            background-color: #8b4513;
            color: white;
            border: none;
            border-radius: 4px;
            cursor: pointer;
            font-size: 16px;
            transition: background-color 0.3s;
        }
        button:hover {
            background-color: #a0522d;
        }
        button:disabled {
            background-color: #cccccc;
            cursor: not-allowed;
        }
        .board {
            display: grid;
            grid-template-columns: repeat(15, 30px);
            grid-template-rows: repeat(15, 30px);
            background-color: #deb887;
            border: 2px solid #8b4513;
            position: relative;
        }
        .cell {
            width: 30px;
            height: 30px;
            box-sizing: border-box;
            position: relative;
            cursor: pointer;
        }
        .cell::before, .cell::after {
            content: '';
            position: absolute;
            background-color: #000;
        }
        .cell::before {
            width: 100%;
            height: 1px;
            top: 50%;
            left: 0;
            transform: translateY(-50%);
        }
        .cell::after {
            width: 1px;
            height: 100%;
            left: 50%;
            top: 0;
            transform: translateX(-50%);
        }
        .stone {
            position: absolute;
            width: 26px;
            height: 26px;
            border-radius: 50%;
            top: 50%;
            left: 50%;
            transform: translate(-50%, -50%);
            z-index: 1;
        }
        .black {
            background: radial-gradient(circle at 30% 30%, #666, #000);
            box-shadow: 1px 1px 2px rgba(0, 0, 0, 0.7);
        }
        .white {
            background: radial-gradient(circle at 30% 30%, #fff, #ccc);
            box-shadow: 1px 1px 2px rgba(0, 0, 0, 0.5);
        }
        .last-move {
            box-shadow: 0 0 0 2px red;
        }
        .status {
            margin-top: 20px;
            font-size: 18px;
            font-weight: bold;
            color: #8b4513;
            height: 24px;
        }
    </style>
</head>
<body>
    <h1>五子棋人机对战</h1>
    <div class="game-container">
        <div class="controls">
            <button id="player-first">玩家先手</button>
            <button id="computer-first">电脑先手</button>
            <button id="restart">重新开始</button>
        </div>
        <div class="board" id="board"></div>
        <div class="status" id="status">请选择先手方开始游戏</div>
    </div>

    <script>
        document.addEventListener('DOMContentLoaded', function() {
            const boardElement = document.getElementById('board');
            const statusElement = document.getElementById('status');
            const playerFirstBtn = document.getElementById('player-first');
            const computerFirstBtn = document.getElementById('computer-first');
            const restartBtn = document.getElementById('restart');
            
            const BOARD_SIZE = 15;
            const EMPTY = 0;
            const PLAYER = 1;
            const COMPUTER = 2;
            
            let board = Array(BOARD_SIZE).fill().map(() => Array(BOARD_SIZE).fill(EMPTY));
            let gameOver = false;
            let currentPlayer = PLAYER;
            let lastMove = null;
            
            // 初始化棋盘
            function initBoard() {
                boardElement.innerHTML = '';
                board = Array(BOARD_SIZE).fill().map(() => Array(BOARD_SIZE).fill(EMPTY));
                gameOver = false;
                lastMove = null;
                
                for (let i = 0; i < BOARD_SIZE; i++) {
                    for (let j = 0; j < BOARD_SIZE; j++) {
                        const cell = document.createElement('div');
                        cell.className = 'cell';
                        cell.dataset.row = i;
                        cell.dataset.col = j;
                        cell.addEventListener('click', () => handleCellClick(i, j));
                        boardElement.appendChild(cell);
                    }
                }
                
                updateStatus();
            }
            
            // 处理点击事件
            function handleCellClick(row, col) {
                if (gameOver || currentPlayer !== PLAYER || board[row][col] !== EMPTY) {
                    return;
                }
                
                makeMove(row, col, PLAYER);
                
                if (!gameOver) {
                    setTimeout(computerMove, 500);
                }
            }
            
            // 落子
            function makeMove(row, col, player) {
                board[row][col] = player;
                renderMove(row, col, player);
                lastMove = {row, col};
                
                if (checkWin(row, col, player)) {
                    gameOver = true;
                    const winner = player === PLAYER ? '玩家' : '电脑';
                    statusElement.textContent = `${winner}获胜！`;
                    return;
                }
                
                if (isBoardFull()) {
                    gameOver = true;
                    statusElement.textContent = '平局！';
                    return;
                }
                
                currentPlayer = currentPlayer === PLAYER ? COMPUTER : PLAYER;
                updateStatus();
            }
            
            // 渲染棋子
            function renderMove(row, col, player) {
                const cellIndex = row * BOARD_SIZE + col;
                const cell = boardElement.children[cellIndex];
                
                const stone = document.createElement('div');
                stone.className = `stone ${player === PLAYER ? 'black' : 'white'}`;
                cell.appendChild(stone);
                
                // 移除上一个最后落子的标记
                if (lastMove) {
                    const lastCellIndex = lastMove.row * BOARD_SIZE + lastMove.col;
                    const lastCell = boardElement.children[lastCellIndex];
                    lastCell.classList.remove('last-move');
                }
                
                // 标记当前最后落子
                cell.classList.add('last-move');
            }
            
            // 检查是否获胜
            function checkWin(row, col, player) {
                const directions = [
                    [0, 1],   // 水平
                    [1, 0],   // 垂直
                    [1, 1],   // 对角线
                    [1, -1]   // 反对角线
                ];
                
                for (const [dx, dy] of directions) {
                    let count = 1;
                    
                    // 正向检查
                    for (let i = 1; i <= 4; i++) {
                        const newRow = row + i * dx;
                        const newCol = col + i * dy;
                        if (newRow < 0 || newRow >= BOARD_SIZE || newCol < 0 || newCol >= BOARD_SIZE || board[newRow][newCol] !== player) {
                            break;
                        }
                        count++;
                    }
                    
                    // 反向检查
                    for (let i = 1; i <= 4; i++) {
                        const newRow = row - i * dx;
                        const newCol = col - i * dy;
                        if (newRow < 0 || newRow >= BOARD_SIZE || newCol < 0 || newCol >= BOARD_SIZE || board[newRow][newCol] !== player) {
                            break;
                        }
                        count++;
                    }
                    
                    if (count >= 5) {
                        return true;
                    }
                }
                
                return false;
            }
            
            // 检查棋盘是否已满
            function isBoardFull() {
                return board.every(row => row.every(cell => cell !== EMPTY));
            }
            
            // 更新状态显示
            function updateStatus() {
                if (gameOver) return;
                statusElement.textContent = currentPlayer === PLAYER ? '轮到玩家落子' : '电脑思考中...';
            }
            
            // 电脑走棋
            function computerMove() {
                if (gameOver || currentPlayer !== COMPUTER) {
                    return;
                }
                
                const [row, col] = findBestMove();
                makeMove(row, col, COMPUTER);
            }
            
            // 寻找最佳落子位置
            function findBestMove() {
                // 1. 检查电脑是否有四连可以获胜
                for (let i = 0; i < BOARD_SIZE; i++) {
                    for (let j = 0; j < BOARD_SIZE; j++) {
                        if (board[i][j] === EMPTY) {
                            board[i][j] = COMPUTER;
                            if (checkWin(i, j, COMPUTER)) {
                                board[i][j] = EMPTY;
                                return [i, j];
                            }
                            board[i][j] = EMPTY;
                        }
                    }
                }
                
                // 2. 检查玩家是否有四连需要防守
                for (let i = 0; i < BOARD_SIZE; i++) {
                    for (let j = 0; j < BOARD_SIZE; j++) {
                        if (board[i][j] === EMPTY) {
                            board[i][j] = PLAYER;
                            if (checkWin(i, j, PLAYER)) {
                                board[i][j] = EMPTY;
                                return [i, j];
                            }
                            board[i][j] = EMPTY;
                        }
                    }
                }
                
                // 3. 评估每个空位的得分
                let bestScore = -Infinity;
                let bestMoves = [];
                
                for (let i = 0; i < BOARD_SIZE; i++) {
                    for (let j = 0; j < BOARD_SIZE; j++) {
                        if (board[i][j] === EMPTY) {
                            const score = evaluatePosition(i, j);
                            if (score > bestScore) {
                                bestScore = score;
                                bestMoves = [[i, j]];
                            } else if (score === bestScore) {
                                bestMoves.push([i, j]);
                            }
                        }
                    }
                }
                
                // 随机选择一个最佳位置
                return bestMoves[Math.floor(Math.random() * bestMoves.length)];
            }
            
            // 评估位置得分
            function evaluatePosition(row, col) {
                let score = 0;
                
                // 中心位置更有价值
                const center = (BOARD_SIZE - 1) / 2;
                const distanceToCenter = Math.sqrt(Math.pow(row - center, 2) + Math.pow(col - center, 2));
                score += (BOARD_SIZE - distanceToCenter) * 0.5;
                
                // 检查四个方向
                const directions = [
                    [0, 1],   // 水平
                    [1, 0],   // 垂直
                    [1, 1],   // 对角线
                    [1, -1]   // 反对角线
                ];
                
                for (const [dx, dy] of directions) {
                    // 检查电脑的连子情况
                    let computerCount = 1; // 当前位置
                    let openEnds = 0;
                    
                    // 正向检查
                    for (let i = 1; i <= 4; i++) {
                        const newRow = row + i * dx;
                        const newCol = col + i * dy;
                        if (newRow < 0 || newRow >= BOARD_SIZE || newCol < 0 || newCol >= BOARD_SIZE) {
                            break;
                        }
                        if (board[newRow][newCol] === COMPUTER) {
                            computerCount++;
                        } else if (board[newRow][newCol] === EMPTY) {
                            openEnds++;
                            break;
                        } else {
                            break;
                        }
                    }
                    
                    // 反向检查
                    for (let i = 1; i <= 4; i++) {
                        const newRow = row - i * dx;
                        const newCol = col - i * dy;
                        if (newRow < 0 || newRow >= BOARD_SIZE || newCol < 0 || newCol >= BOARD_SIZE) {
                            break;
                        }
                        if (board[newRow][newCol] === COMPUTER) {
                            computerCount++;
                        } else if (board[newRow][newCol] === EMPTY) {
                            openEnds++;
                            break;
                        } else {
                            break;
                        }
                    }
                    
                    // 根据连子数和开放端加分
                    if (computerCount >= 4) {
                        score += 10000;
                    } else if (computerCount === 3) {
                        score += openEnds === 2 ? 1000 : 100;
                    } else if (computerCount === 2) {
                        score += openEnds === 2 ? 10 : 5;
                    } else if (computerCount === 1) {
                        score += 1;
                    }
                    
                    // 检查玩家的连子情况
                    let playerCount = 0;
                    openEnds = 0;
                    
                    // 正向检查
                    for (let i = 1; i <= 4; i++) {
                        const newRow = row + i * dx;
                        const newCol = col + i * dy;
                        if (newRow < 0 || newRow >= BOARD_SIZE || newCol < 0 || newCol >= BOARD_SIZE) {
                            break;
                        }
                        if (board[newRow][newCol] === PLAYER) {
                            playerCount++;
                        } else if (board[newRow][newCol] === EMPTY) {
                            openEnds++;
                            break;
                        } else {
                            break;
                        }
                    }
                    
                    // 反向检查
                    for (let i = 1; i <= 4; i++) {
                        const newRow = row - i * dx;
                        const newCol = col - i * dy;
                        if (newRow < 0 || newRow >= BOARD_SIZE || newCol < 0 || newCol >= BOARD_SIZE) {
                            break;
                        }
                        if (board[newRow][newCol] === PLAYER) {
                            playerCount++;
                        } else if (board[newRow][newCol] === EMPTY) {
                            openEnds++;
                            break;
                        } else {
                            break;
                        }
                    }
                    
                    // 根据玩家的连子情况防守
                    if (playerCount >= 4) {
                        score += 5000;
                    } else if (playerCount === 3) {
                        score += openEnds === 2 ? 500 : 50;
                    } else if (playerCount === 2) {
                        score += openEnds === 2 ? 5 : 2;
                    }
                }
                
                return score;
            }
            
            // 开始游戏（玩家先手）
            function startPlayerFirst() {
                initBoard();
                currentPlayer = PLAYER;
                statusElement.textContent = '轮到玩家落子';
            }
            
            // 开始游戏（电脑先手）
            function startComputerFirst() {
                initBoard();
                currentPlayer = COMPUTER;
                statusElement.textContent = '电脑思考中...';
                setTimeout(computerMove, 500);
            }
            
            // 重新开始游戏
            function restartGame() {
                if (currentPlayer === PLAYER) {
                    startPlayerFirst();
                } else {
                    startComputerFirst();
                }
            }
            
            // 事件监听
            playerFirstBtn.addEventListener('click', startPlayerFirst);
            computerFirstBtn.addEventListener('click', startComputerFirst);
            restartBtn.addEventListener('click', restartGame);
            
            // 初始化游戏（默认玩家先手）
            startPlayerFirst();
        });
    </script>
</body>
</html>
```

## 游戏特点

1. **游戏界面**：
   - 15×15 标准五子棋棋盘
   - 木质风格的棋盘和棋子
   - 标记最后落子的位置

2. **游戏功能**：
   - 可以选择玩家先手或电脑先手
   - 电脑有基本的 AI 算法，能够进攻和防守
   - 自动判断胜负
   - 可以重新开始游戏

3. **AI 算法**：
   - 优先检查是否有直接获胜的机会
   - 其次检查是否需要防守玩家的四连
   - 使用评分系统评估每个空位的价值
   - 考虑连子数量和开放端数量

4. **用户体验**：
   - 清晰的游戏状态提示
   - 响应式设计
   - 视觉反馈

您可以将上述代码保存为一个 HTML 文件，然后在浏览器中打开即可开始游戏。